package com.sanri.tools.modules.core.service.plugin;

import com.sanri.tools.modules.core.exception.ToolException;
import com.sanri.tools.modules.core.service.SpringUtils;
import com.sanri.tools.modules.core.service.plugin.dtos.InstallPluginInfo;
import com.sanri.tools.modules.core.service.plugin.events.ModuleChangeEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarFile;

@Component
@Slf4j
public class ModuleClassLoaderRepo {

    @Autowired
    private DefaultListableBeanFactory beanFactory;

    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 动态加载的模块列表
     */
    private static final Map<String,ModuleClassLoader> repositoryClassLoader = new ConcurrentHashMap<>();

    /**
     * 模块动态加载
     * @param jarFile
     * @return
     */
    ModuleClassLoader loadJar(File jarFile) throws IOException {
        ModuleClassLoader classLoader = new ModuleClassLoader(jarFile, Thread.currentThread().getContextClassLoader());
        SpringUtils.getBeanFactory().setBeanClassLoader(classLoader);
        Thread.currentThread().setContextClassLoader(classLoader);
        classLoader.initBean();
        return classLoader;
    }

    /**
     * 模块是否加载
     * @param moduleName
     * @return
     */
    public boolean moduleIsLoad(String moduleName){
        return repositoryClassLoader.containsKey(moduleName);
    }

    /**
     * 获取模块的类加载器
     * @param moduleName
     * @return
     */
    public ModuleClassLoader moduleClassLoader(String moduleName){
        return repositoryClassLoader.get(moduleName);
    }

    /**
     * 模块加载
     * @param realInstall
     * @param jarFile
     * @return
     */
    public ModuleClassLoader loadModule(InstallPluginInfo realInstall, File jarFile) throws IOException {
        // 检查模块是否已经加载
        if (repositoryClassLoader.containsKey(realInstall.getPluginId())){
            applicationContext.publishEvent(new ModuleChangeEvent(new JarFile(jarFile), false));
            unLoadModule(realInstall.getPluginId());
        }

        // 重新加载模块
        final ModuleClassLoader moduleClassLoader = loadJar(jarFile);
        repositoryClassLoader.put(realInstall.getPluginId(), moduleClassLoader);

        // 初始化数据加载, 使用事件机制, 把当前的类加载器发出去, 监听到事件的进行当前类加载器的初始化数据加载
        applicationContext.publishEvent(new ModuleChangeEvent(new JarFile(jarFile), true));

        return moduleClassLoader;
    }

    /**
     * 卸载模块
     * @param moduleName
     */
    public void unLoadModule(String moduleName) throws IOException {
        ModuleClassLoader moduleClassLoader = repositoryClassLoader.get(moduleName);
        if (moduleClassLoader == null){
            log.warn("模块[{}]没有被加载", moduleName);
            return;
        }
        List<String> registeredBean = moduleClassLoader.getRegisteredBean();

        for (String beanName : registeredBean) {
            log.info("删除bean:"+beanName);
            beanFactory.removeBeanDefinition(beanName);
        }

        moduleClassLoader.close();
        repositoryClassLoader.remove(moduleName);

    }
}
